﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Citrix.XenApp.Commands;
using Citrix.XaAdminMobile.Util;

namespace Citrix.XaAdminMobile.Model
{
    /// <summary>
    /// Provides a unique key for comparing XASession instances since XASession has no built-in
    /// comparison functions. This is used when we have different instances of XASession
    /// obtained in different SDK calls that we want to test for equality.
    /// </summary>
    /// <remarks>
    /// A XASession object doesn't actually represent a single session. It represents a single
    /// application running in a session. So if the user is using session sharing to run 
    /// multiple apps then we will get multiple session objects for each app running in the
    /// session.
    /// </remarks>
    internal class SessionKey : IEquatable<SessionKey>
    {
        /// <summary>
        /// The session ID.
        /// </summary>
        private readonly int? sessionId;

        /// <summary>
        /// The date/time this session was created.
        /// </summary>
        private readonly DateTime? logonTime;

        /// <summary>
        /// The name of the XenApp server this session is running on.
        /// </summary>
        private readonly string serverName;

        /// <summary>
        /// The account name of the user that owns the session.
        /// </summary>
        private readonly string accountName;

        /// <summary>
        /// The published app name.
        /// </summary>
        private readonly string appName;

        /// <summary>
        /// Used in building a hash code for this class.
        /// </summary>
        private const string HashCodeSeparator = "||";

        /// <summary>
        /// Ctor
        /// </summary>
        /// <param name="source">Source session object we are a key for.</param>
        /// <exception cref="ArgumentNullException">Thrown if <paramref name="source"/> is null.</exception>
        public SessionKey(XASession source)
        {
            if (null == source)
            {
                throw new ArgumentNullException("source");
            }

            this.sessionId = source.SessionId;
            this.logonTime = source.LogOnTime;
            this.serverName = source.ServerName;
            this.accountName = source.AccountName;
            this.appName = source.BrowserName;
        }

        /// <summary>
        /// IEquatable implementation to test for equality.
        /// </summary>
        /// <param name="other">Source to compare against.</param>
        /// <returns>True if equal, false if not.</returns>
        public bool Equals(SessionKey other)
        {
            return (other != null) &&
                (this.sessionId == other.sessionId) &&
                (this.logonTime == other.logonTime) &&
                (0 == string.CompareOrdinal(this.serverName, other.serverName)) &&
                (0 == string.CompareOrdinal(this.accountName, other.accountName)) &&
                (0 == string.CompareOrdinal(this.appName, other.appName));
        }

        /// <summary>
        /// Object.Equals override.
        /// </summary>
        /// <param name="obj">Source to compare against.</param>
        /// <returns>True if equal, false if not.</returns>
        public override bool Equals(object obj)
        {
            if (obj != null && (obj is SessionKey))
            {
                return Equals((SessionKey)obj);
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// Returns a hash code for this instance.
        /// </summary>
        /// <returns>Hashcode.</returns>
        public override int GetHashCode()
        {
            // Build a hash code based off the properties we use for equality testing.
            StringBuilder builder = new StringBuilder();
            builder.Append(this.sessionId.HasValue ? this.sessionId.Value : -1);
            builder.Append(HashCodeSeparator);
            builder.Append(this.logonTime.HasValue ? this.logonTime.Value.Ticks : -1);
            builder.Append(HashCodeSeparator);
            builder.Append(this.serverName);
            builder.Append(HashCodeSeparator);
            builder.Append(this.accountName);
            builder.Append(HashCodeSeparator);
            builder.Append(this.appName);
            return builder.ToString().GetHashCode();
        }
    }
}